using System;
using System.Diagnostics;
using ErrorDumper.Filtering;
using ErrorDumper.Processing;
using ErrorDumper.Writing;

namespace ErrorDumper {
    public class DefaultExceptionHandler : IExceptionHandler {

        public virtual string HandleException(ExceptionPropertyCollection properties, Exception exception) {
            try {
                if (properties == null)
                    properties = new ExceptionPropertyCollection();

                if (exception != null) {
                    ExceptionPropertyCollection.Build(exception, properties, false);

                    if (!properties.Contains(ExceptionProperty.ClassName))
                        properties[ExceptionProperty.ClassName] = exception.GetType().Name;

                    if (!properties.Contains(ExceptionProperty.ClassFullName))
                        properties[ExceptionProperty.ClassFullName] = exception.GetType().FullName;

                    if (!properties.Contains(ExceptionProperty.Message))
                        properties[ExceptionProperty.Message] = exception.Message;
                }

                var level = ExceptionFilters.GetLevel(properties, exception);

                var context = new ExceptionProcessorContext(properties, exception) {
                    HandlingLevel = level
                };

                ExceptionProcessors.ProcessException(context);
                properties = context.Properties;
                var content = context.Content;
                level = context.HandlingLevel;

                Trace.TraceError("DefaultExceptionHandler : HandleException : Exception handled with level {0}. {1}",
                                 level, Convert.ToString(exception));

                switch (level) {
                    case ExceptionHandlingLevel.Ignore:
                        return null;

                    case ExceptionHandlingLevel.WriteProperties:
                        return WriteException(properties, null);

                    case ExceptionHandlingLevel.WriteContent:
                        if (content == null)
                            content = ExceptionSerializer.SerializeException(
                                properties, exception, ExceptionSerializationOptions.MinimumSerialization);
                        return WriteException(properties, content);

                    case ExceptionHandlingLevel.WriteExtendedDump:
                        if (content == null)
                            content = ExceptionSerializer.SerializeException(
                                properties, exception, ExceptionSerializationOptions.MaximumSerialization);
                        return WriteException(properties, content);

                    default:
                        throw new NotSupportedException(level.ToString());
                }
            }
            catch (Exception internalException) {
                ExceptionWriters.WriteInternalExceptionSafely(internalException, exception);
                return ExceptionWriters.WriteExceptionSafely(properties, exception);
            }
        }

        public virtual string HandleException(ExceptionPropertyCollection properties, string content) {
            try {
                Trace.TraceError("DefaultExceptionHandler : HandleException : Handling exception: {0}", content);

                var level = ExceptionFilters.GetLevel(properties, content);

                var context = new ExceptionProcessorContext(properties) {
                    Content = content,
                    HandlingLevel = level
                };

                ExceptionProcessors.ProcessException(context);
                properties = context.Properties;
                content = context.Content;
                level = context.HandlingLevel;

                Trace.TraceError("DefaultExceptionHandler : HandleException : Exception handled with level {0}. {1}",
                                 level, content);

                switch (level) {
                    case ExceptionHandlingLevel.Ignore:
                        return null;

                    case ExceptionHandlingLevel.WriteProperties:
                        return WriteException(properties, null);

                    case ExceptionHandlingLevel.WriteContent:
                        goto case ExceptionHandlingLevel.WriteExtendedDump;

                    case ExceptionHandlingLevel.WriteExtendedDump:
                        return WriteException(properties, content);

                    default:
                        throw new NotSupportedException(level.ToString());
                }
            }
            catch (Exception internalException) {
                ExceptionWriters.WriteInternalExceptionSafely(internalException, content);
                return ExceptionWriters.WriteExceptionSafely(properties, content);
            }
        }

        protected virtual string WriteException(ExceptionPropertyCollection properties, string content) {
            return ExceptionWriters.WriteExceptionSafely(properties, content);
        }
    }
}
